Using SOS with TurboVision(tm) ============================== TurboVision (TV) is written in C++ and so is SOS. This fact makes using them together even easier! The class TSerial serves to encapsulate all handling of serial ports at the top level of your TApplication. Normally you would just inherit TSerial and TApplication as public in your application class. This is by no means the only way to use SOS and TV together, but for most purposes it will get you off on the right foot. As shown, all serial events are BROADCAST to every view in YOUR application class (TMyApp). This means that ANY view can respond to the event. For example, a custom TWindow class can be derived to act as a terminal screen by defining a new handleEvent() for the derived class. This new event handler could be made to respond to a cmRxData command of an evSerial event, and display received data in the window. The code below for TSerial and TMyApp IS NOT COMPLETE; YOU have to finish their definitions. The constructor for TMyApp also MUST initialize the pointer "modem". YOU must enable evSerial events in the constructor of all classes that will respond to them by the following: // Enable evSerial events eventMask |= evSerial; Make sure to use reasonably large receive and transmit queues, or you might find your application slowing up when you do serial I/O (busy wait for queues to be available). In most cases, a receive queue of 8192, and a transmit queue of 2048 will be more than ample. At higher speeds you will need to increase the receive queue size. /* TVSERIAL.H ***************************************************************/ #include "modem.h" // A few IMPORTANT constants const short evSerial = 0x0400; const short cmFind = 0; const short cmNoCarrier = 1; const short cmOffline = 2; const short cmRxErrors = 3; const short cmRxData = 4; class TSerial { private: Boolean dcd; Boolean dsr; protected: Modem *modem; public: void GetSerialEvent( TEvent &event ); void HandleSerialEvent( TEvent &event ); }; /* TVSERIAL.CPP *************************************************************/ #include #include "tvserial.h" void TSerial::GetSerialEvent( TEvent &event ) { // Do nothing if an event already exists if( event.what == evNothing ) { // Get the status of DCD and DSR signals (from modem) Boolean newDCD = modem->NoCarrier(); Boolean newDSR = modem->GetDSR(); // Check for DCD loss if( newDCD && newDCD != dcd ) { dcd = newDCD; event.what = evSerial; event.message.command = cmNoCarrier; event.message.infoPtr = ( void * ) modem; } // Check for DSR loss else if( newDSR && newDSR != dsr ) { dsr = newDSR; event.what = evSerial; event.message.command = cmOffline; event.message.infoPtr = ( void * ) modem; } // Check for errors in received data else if( modem->AnyErrors() ) { event.what = evSerial; event.message.command = cmRxErrors; event.message.infoPtr = ( void * ) modem; } // Check for received data else if( !modem->RxIsEmpty() ) { event.what = evSerial; event.message.command = cmRxData; event.message.infoPtr = ( void * ) modem; } } } void TSerial::HandleSerialEvent( TEvent &event ) { // Handle all evSerial events if( event.what == evSerial ) { // Event handled flag (True = DO NOT BROADCAST EVENT!) Boolean eventOK = True; switch( event.message.command ) { case cmFind: // // This command is intended for use with message(). // If a TV object you have derived needs to access the serial port, // for example to transmit data, then cmFind can be used to get // a pointer to the modem object. // // Example: // Modem *modem = ( Modem * ) message( TApplication::application, // evSerial, // cmFind, // 0 // ); // ( *modem ) << "Text string to transmit"; // // NOTE: an assumption is made that the pointer "modem" will // always be valid! // break; case cmNoCarrier: // // Call YOUR routine to handle loss of carrier (modem hangup). // Can be left as is to ignore this command. // break; case cmOffline: // // Call YOUR routine to handle device not ready. // Can be left as is to ignore this command. // break; case cmRxErrors: // // Call YOUR routine to handle received data errors // Can be left as is to ignore this command. // modem->ClearErrors(); break; case cmRxData: // // Call YOUR routine to handle received data, and COMMENT OUT // the statement "eventOK = False;". // // Normally ONLY windows and such respond to these events, // so normally you don't call anything here. // eventOK = False; break; default: // // Unknown commands end up here // break; } // Clear the event (mark it as handled). // Events that are cleared here ARE NOT BRODCASTED! if( eventOK ) { event.what = evNothing; event.infoPtr = ( void * ) modem; } } } /* TMYAPP.H *****************************************************************/ #define Uses_TApplication #include #include "tvserial.h" // A skeleton for YOUR application class class TMyApp : public TApplication, public TSerial { public: virtual void getEvent( TEvent &event ); virtual void handleEvent( TEvent &event ); }; /* TMYAPP.CPP ***************************************************************/ #include "tmyapp.h" // Add your event handlers! void TMyApp::handleEvent( TEvent *event ) { TApplication::handleEvent( event ); TSerial::HandleSerialEvent( event ); if( event.what != evNothing ) { // YOUR normal code for top level application events goes here. // After handling an event you MUST: clearEvent( event ); } } // No need to change this function void TMyApp::getEvent( TEvent &event ) { TApplication::getEvent( event ); TSerial::GetSerialEvent( event ); } /****************************************************************************/